package bgai.gui;

import java.awt.Button;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.OceanTheme;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

import bgai.ai.minimax.BoardType;
import bgai.ai.minimax.Search;
import bgai.gamelogic.Backgammon;
import bgai.gamelogic.BackgammonError;
import bgai.gamelogic.BadMoveException;
import bgai.gamelogic.CheckerColor;
import bgai.gamelogic.CheckerMove;
import bgai.gamelogic.DiceException;
import bgai.gamelogic.Move;
import bgai.gamelogic.Point;
import bgai.gamelogic.PositionException;
import bgai.gamelogic.SingleMove;
import bgai.players.AbstractPlayer;
import bgai.players.Player;

/**
 * In questa classe vengono gestite le interazioni del player con la board
 */
public class BackgammonGUI extends JFrame implements ActionListener, MouseListener, WindowListener {

	private static final long serialVersionUID = -5997311744703544277L;

	/**
	 * I secondi che l'IA attende prima di eseguire la sua mossa
	 */
	 private static final int SECONDS=0;
	
	/**
	 * player bianco
	 */
	private Player whitePl;

	/**
	 * player nero
	 */
	private Player blackPl;

	/**
	 * L'istanza Backgammon associata
	 */
	private Backgammon bg;

	/**
	 * la finestra di vittoria
	 */
	private JDialog endWind;

	/**
	 * la finestra di inizio gioco
	 */
	private JFrame initWindow;

	/**
	 * Array per avere un riferimento ai 24 point dell'interfaccia grafica
	 */
	private ArrayList<PointLabel> pointsList;

	/**
	 * I 2 dadi
	 */
	private Dice dice1;
	private Dice dice2;
	
	/**
	 * I tasti per mostrare per eseguire le IA step-by-step
	 */
	private JButton pauseBtn,stepBtn;
	
	/**
	 * true se la pausa e' attiva
	 */
	private boolean pauseEnabled;

	/**
	 * Variabile di comodo che dice se ci sono placeholder visualizzati su una delle tavole
	 */
	private boolean isPlaceholderShown;

	/**
	 * La lista delle possibili mosse che il player puo' compiere.
	 * Viene riempita in seguito al lancio dei dadi
	 * Durante il turno del player che ha tirato i dadi man mano che questo esegue le sue mosse la lista viene svuotata.
	 */
	/**
	 * Mosse che il player corrente ha fatto finora.
	 * Durante il turno del player che ha tirato i dadi man mano che questo 
	 * esegue le sue mosse queste vengono aggiunte a questo oggetto.
	 */
	private Move move;

	/**
	 * La posizione della pedina che il player vuole spostare. Serve per memorizzare temporaneamente la posizione iniziale dello spostamento
	 */
	private int initPos;

	/**
	 * la bar in cui vengono posizionate le pedine mangiate
	 */
	private Bar bar;

	/**
	 * la barra in cui sono presenti le pedine portate fuori
	 */
	private BearOffBar bearOffBar;

	/**
	 * Costruttore per il caso di umano vs. umano
	 * @param bgm l'istanza backgammon associata
	 */
	BackgammonGUI(Backgammon bgm){

		bg=bgm;
		whitePl= bg.getWhitePlayer();
		blackPl= bg.getBlackPlayer();

		initPos=-10;
		pointsList = new ArrayList<PointLabel>();
		pointsList.addAll(Collections.<PointLabel>nCopies(24, null));
		createGUI();

	}

	/**
	 * Crea l'interfaccia grafica
	 */
	private void createGUI(){

		try {
			// Imposta il L&F multi-piattaforma di Java ("Metal") con il tema di default (da Java SE 5) "Ocean" 
			UIManager.setLookAndFeel(
					UIManager.getCrossPlatformLookAndFeelClassName());
			MetalLookAndFeel.setCurrentTheme(new OceanTheme());
		} 
		catch (UnsupportedLookAndFeelException e) {
			System.err.println("Non posso usare il look and feel specificato");		
		}
		catch (ClassNotFoundException e) {
			System.err.println("Non e' possibile trovare la classe del look and feel specificato");	
		}
		catch (Exception e){
			System.err.println("L&F non impostato");
		}

		this.setTitle("BackGammon");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Di default chiude il gioco	
		this.setBounds(new Rectangle(1000, 600));
		this.setResizable(false);

		System.out.println("JFrame --> "+ this.getWidth() +", "+this.getHeight());

		Color tableColor = new Color(139,69,19);


		JPanel containsAll = new JPanel(); //Questo usa BoxLayout
		containsAll.setLayout(new BoxLayout(containsAll, BoxLayout.LINE_AXIS));
		containsAll.setBackground(tableColor);
		containsAll.setBounds(new Rectangle(this.getWidth(), this.getHeight()));
		System.out.println("containsAll --> "+ containsAll.getWidth() +", "+containsAll.getHeight());


		//barra sinistra
		JPanel leftBar = new JPanel(); 
		leftBar.setBackground(tableColor);
		float percWidth= ((float) 5/100) * this.getWidth();
		leftBar.setBounds(new Rectangle((int)percWidth, this.getHeight()));
		System.out.println("leftBar --> "+ leftBar.getWidth() +", "+leftBar.getHeight());


		JPanel leftPanel = new JPanel(); 
		leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
		leftPanel.setBackground(tableColor);
		percWidth= ((float) 35/100) * this.getWidth();
		leftPanel.setBounds(new Rectangle((int)percWidth, this.getHeight()));
		System.out.println("leftPanel --> "+ leftPanel.getWidth() +", "+leftPanel.getHeight());


		// aggiungo i numeri sopra i point nella tavola esterna
		JPanel numUpExtTable= new JPanel();
		numUpExtTable.setLayout(new GridLayout(1, 6));
		numUpExtTable.setBackground(tableColor);
		percWidth= ((float) 35/100) * this.getWidth();
		float percHeight= ((float) 10/100) * this.getHeight();
		numUpExtTable.setBounds(new Rectangle((int)percWidth, (int) percHeight));
		System.out.println("numUpExtTable --> "+ numUpExtTable.getWidth() +", "+numUpExtTable.getHeight());


		for(int i=13;i<=18;i++){
			JLabel l=new JLabel(""+i);
			l.setForeground(Color.WHITE);
			l.setHorizontalAlignment(SwingConstants.CENTER);
			numUpExtTable.add(l);
		}


		//tavola esterna/sinistra (usa BorderLayout)
		JPanel externTable = new JPanel();
		externTable.setBackground(tableColor);
		externTable.setLayout(new GridLayout(2,6));	
		percWidth= ((float) 35/100) * this.getWidth();
		percHeight= ((float) 80/100) * this.getHeight();
		externTable.setBounds(new Rectangle((int)percWidth, (int)percHeight));
		System.out.println("externTable --> "+ externTable.getWidth() +", "+externTable.getHeight());


		// aggiungo point a tavola esterna

		for(int i=13;i<=18;i++){

			PointLabel pointL = null;

			if(i%2==0){
				pointL= new PointLabel(CheckerColor.BLACK,bg.getPoint(i),this);
			}

			else {
				pointL= new PointLabel(CheckerColor.WHITE,bg.getPoint(i),this);
			}

			pointsList.set(i-1, pointL);
			externTable.add(pointL);

		}

		for(int i=12;i>=7;i--){

			PointLabel pointL = null;

			if(i%2==0){
				pointL= new PointLabel(CheckerColor.BLACK,bg.getPoint(i),this);	
			}

			else {
				pointL= new PointLabel(CheckerColor.WHITE,bg.getPoint(i),this);
			}

			pointsList.set(i-1, pointL);
			externTable.add(pointL);

		}


		//aggiungo i numeri sotto i point nella tavola esterna
		JPanel numDownExtTable= new JPanel();
		numDownExtTable.setLayout(new GridLayout(1, 6));		
		numDownExtTable.setBackground(tableColor);
		percWidth= ((float) 35/100) * this.getWidth();
		percHeight= ((float) 10/100) * this.getHeight();
		numDownExtTable.setBounds(new Rectangle((int) percWidth, (int)percHeight));
		System.out.println("numDownExtTable --> "+ numDownExtTable.getWidth() +", "+numDownExtTable.getHeight());

		for(int i=12;i>=7;i--){
			JLabel l=new JLabel(""+i);
			l.setForeground(Color.WHITE);
			l.setHorizontalAlignment(SwingConstants.CENTER);
			numDownExtTable.add(l);
		}


		//dove vengono situate pedine mangiate
		bar = new Bar(this);


		JPanel rightPanel = new JPanel(); 
		rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));
		rightPanel.setBackground(tableColor);
		percWidth= ((float) 35/100) * this.getWidth();
		rightPanel.setBounds(new Rectangle((int) percWidth, this.getHeight()));
		System.out.println("rightPanel --> "+ rightPanel.getWidth() +", "+rightPanel.getHeight());


		// aggiungo i numeri sopra i point nella tavola interna
		JPanel numUpIntTable= new JPanel();
		numUpIntTable.setLayout(new GridLayout(1, 6));
		numUpIntTable.setBackground(tableColor);
		percWidth= ((float) 35/100) * this.getWidth();
		percHeight= ((float) 10/100) * this.getHeight();
		numUpIntTable.setBounds(new Rectangle((int) percWidth, (int)percHeight));
		System.out.println("numUpIntTable --> "+ numUpIntTable.getWidth() +", "+numUpIntTable.getHeight());


		for(int i=19;i<=24;i++){
			JLabel l=new JLabel(""+i);
			l.setForeground(Color.WHITE);
			l.setHorizontalAlignment(SwingConstants.CENTER);
			numUpIntTable.add(l);
		}


		//tavola interna/destra (usa BoxLayout)
		JPanel internalTable = new JPanel();
		internalTable.setBackground(tableColor);
		internalTable.setLayout(new GridLayout(2,6));
		percWidth= ((float) 35/100) * this.getWidth();
		percHeight= ((float) 80/100) * this.getHeight();
		internalTable.setBounds(new Rectangle((int)percWidth, (int)percHeight));
		System.out.println("internalTable --> "+ internalTable.getWidth() +", "+internalTable.getHeight());


		// aggiungo point a tavola esterna

		for(int i=19;i<=24;i++){

			PointLabel pointL = null;

			if(i%2==0){
				pointL= new PointLabel(CheckerColor.BLACK,bg.getPoint(i),this);	
			}

			else {
				pointL= new PointLabel(CheckerColor.WHITE,bg.getPoint(i),this);
			}

			pointsList.set(i-1, pointL);
			internalTable.add(pointL);

		}

		for(int i=6;i>=1;i--){

			PointLabel pointL = null;

			if(i%2==0){
				pointL= new PointLabel(CheckerColor.BLACK,bg.getPoint(i),this);
			}

			else {
				pointL= new PointLabel(CheckerColor.WHITE,bg.getPoint(i),this);
			}

			pointsList.set(i-1, pointL);
			internalTable.add(pointL);

		}



		//aggiungo i numeri sotto i point nella tavola esterna
		JPanel numDownIntTable= new JPanel();
		numDownIntTable.setLayout(new GridLayout(1, 6));
		numDownIntTable.setBackground(tableColor);
		percWidth= ((float) 35/100) * this.getWidth();
		percHeight= ((float) 10/100) * this.getHeight();
		numDownIntTable.setBounds(new Rectangle((int)percWidth, (int) percHeight));
		System.out.println("numDownIntTable --> "+ numDownIntTable.getWidth() +", "+numDownIntTable.getHeight());


		for(int i=6;i>=1;i--){
			JLabel l=new JLabel(""+i);
			l.setForeground(Color.WHITE);
			l.setHorizontalAlignment(SwingConstants.CENTER);
			numDownIntTable.add(l);
		}


		// La barra a destra che contiene i dadi, la bearOffBar ed i tasti pause e step
		JPanel rightBarContainer = new JPanel();
		rightBarContainer.setBackground(tableColor);
		rightBarContainer.setLayout(new BoxLayout(rightBarContainer, BoxLayout.PAGE_AXIS));
		percWidth= ((float) 20/100) * this.getWidth();
		rightBarContainer.setBounds(new Rectangle((int)percWidth, this.getHeight()));
		System.out.println("rightBarContainer --> "+ rightBarContainer.getWidth() +", "+rightBarContainer.getHeight());


		// contenitore dei tasti
		
		JPanel btnContainer=new JPanel();
		btnContainer.setBackground(tableColor);
		btnContainer.setLayout(new BoxLayout(btnContainer, BoxLayout.LINE_AXIS));
		
		Border emptyBorder = BorderFactory.createEmptyBorder();
		
		// i tasti pause & step
		//TODO sostituire i 2 tasti con icone
		pauseBtn=new JButton();
		pauseBtn.setBackground(tableColor);
		pauseBtn.addActionListener(this);
		pauseBtn.setBorder(emptyBorder);
		pauseBtn.setActionCommand("pause");

		
		stepBtn=new JButton();
		stepBtn.setBackground(tableColor);
		stepBtn.setBorder(emptyBorder);
		stepBtn.addActionListener(this);
		stepBtn.setActionCommand("step");
		try {
		    Image img = ImageIO.read(BackgammonGUI.class.getResource("/img/step.png"));
		    img=img.getScaledInstance(50, 50, Image.SCALE_SMOOTH);
		    stepBtn.setIcon(new ImageIcon(img));
		  } catch (IOException ex) {
		  }
		stepBtn.setEnabled(false); // verra' attivato automaticamente in seguito se la pausa e' attiva
		
		btnContainer.add(pauseBtn);
		btnContainer.add(Box.createRigidArea(new Dimension(20,0)));
		btnContainer.add(stepBtn);
		
		// tasto pausa e tasto fotogramma vanno disattivati se un player e' umano
		if(whitePl.isHuman() || blackPl.isHuman()){
			pauseBtn.setEnabled(false);
			pauseEnabled=false;
			try {
			    Image img = ImageIO.read(BackgammonGUI.class.getResource("/img/pause.png"));
			    img=img.getScaledInstance(50, 50, Image.SCALE_SMOOTH);
			    pauseBtn.setIcon(new ImageIcon(img));
			  } catch (IOException ex) {
			  }
			
		} else{
			//se invece sono 2 computer allora abilita gia' la pausa
			pauseEnabled=true;
			try {
			    Image img = ImageIO.read(BackgammonGUI.class.getResource("/img/play.png"));
			    img=img.getScaledInstance(50, 50, Image.SCALE_SMOOTH);
			    pauseBtn.setIcon(new ImageIcon(img));
			  } catch (IOException ex) {
			  }
			
		}
		
		//barra in cui sono presenti le pedine portate fuori ed i dadi
		bearOffBar = new BearOffBar(this);

		JPanel dicesPanel=new JPanel();
		dicesPanel.setBackground(tableColor);

		//pannello che contiene i 2 dadi
		JPanel dicesContainer= new JPanel();
		dicesContainer.setBackground(tableColor);
		//dicesContainer.setBorder(BorderFactory.createLineBorder(Color.red));


		// i dadi da gioco
		dice1 = new Dice(Color.BLACK,Color.WHITE);
		dice2 = new Dice(Color.WHITE,Color.BLACK);


		dice1.setCursor(null);
		dice1.addActionListener(this);
		dice1.setActionCommand("Dice1");
		dice1.setEnabled(false);
		dice1.setContentAreaFilled(false);
		dice1.setFocusPainted(false);
		dice1.setBorder(BorderFactory.createEmptyBorder());

		dice2.setCursor(null);
		dice2.addActionListener(this);
		dice2.setActionCommand("Dice2");
		dice2.setEnabled(false);
		dice2.setContentAreaFilled(false);
		dice2.setFocusPainted(false);
		dice2.setBorder(BorderFactory.createEmptyBorder());

		leftPanel.add(numUpExtTable);
		leftPanel.add(externTable);
		leftPanel.add(numDownExtTable);


		rightPanel.add(numUpIntTable);
		rightPanel.add(internalTable);
		rightPanel.add(numDownIntTable);

		dicesContainer.add(dice1);
		dicesContainer.add(dice2);

		dicesPanel.add(dicesContainer);

		JPanel bearOffPanel= new JPanel();
		bearOffPanel.setBackground(tableColor);

		bearOffPanel.add(bearOffBar);

		rightBarContainer.add(Box.createRigidArea(new Dimension(0,40)));
		rightBarContainer.add(dicesPanel);
		rightBarContainer.add(bearOffPanel);
		rightBarContainer.add(btnContainer);
		rightBarContainer.add(Box.createRigidArea(new Dimension(0,40)));


		containsAll.add(leftBar);
		containsAll.add(leftPanel);
		containsAll.add(bar);
		containsAll.add(rightPanel);
		containsAll.add(rightBarContainer);

		// posiziona le pedine iniziali
		setInitCheckerPosition();

		this.setContentPane(containsAll);

		//this.pack();
		this.setLocationRelativeTo(null); // al centro dello schermo

	}

	/**
	 * Restituisce l'istanza Backgammon associata a BackgammonGUI
	 * @return vedi descrizione metodo
	 */
	public Backgammon getBg(){

		return this.bg;
	}

	/**
	 * Inizia il gioco
	 */
	public void initGame(){


		//si inizia sempre tirando il dado nero

		if(blackPl.isHuman()){ //umano

			// il player nero deve fare click sul dado
			//all'inizio dice1 e' il dado nero
			enableDice(dice1);

		}
		else{ //IA

			int valueBlack= bg.rollDice();

			//tiro automatico
			dice1.setValue(valueBlack);

			System.out.println("Il player nero (IA) ha tirato il dado: "+valueBlack);

			if(whitePl.isHuman()){
				//il player bianco e' umano
				enableDice(dice2);

			}
			else{ //IA

				//tiro automatico
				int valueWhite = bg.rollDice();
				dice2.setValue(valueWhite);
				System.out.println("Il player bianco (IA) ha tirato il dado: "+valueBlack);
				tieBreaker(valueBlack,valueWhite);

			}

		}


	}

	/**
	 * Aggiunge un riferimento alla finestra iniziale di Backgammon per poter riaprirla per ricominciare la partita
	 * @param initWindow il riferimento alla finestra iniziale
	 */
	public void setInitWindow(JFrame initWindow){

		this.initWindow=initWindow;

	}

	/**
	 * Inserisce le pedine nella loro posizione iniziale
	 */
	public void setInitCheckerPosition(){


		//aggiunge checker sui point
		for (Point p : bg) {
			for (int n=0; n<p.getNum(); n++) {
				pointsList.get(p.getPosition()-1).insertChecker(p.getColor(), false);
			}
		}

		//aggiunge checker nella bar

		for(int i=0;i<bg.getBarCheckers(CheckerColor.WHITE);i++){

			bar.addChecker(CheckerColor.WHITE);
		}

		for(int i=0;i<bg.getBarCheckers(CheckerColor.BLACK);i++){

			bar.addChecker(CheckerColor.BLACK);

		}

		//aggiunge checker nella barra bear off

		for(int i=0;i<bg.getBorneOffCheckers(CheckerColor.BLACK);i++){

			bearOffBar.addChecker(CheckerColor.BLACK, false);

		}

		for(int i=0;i<bg.getBorneOffCheckers(CheckerColor.WHITE);i++){

			bearOffBar.addChecker(CheckerColor.WHITE, false);

		}


	}


	/**
	 * Dichiara il vincitore del gioco . Il metodo viene invocato dalla classe Backgammon.
	 * @param playerColor il player che ha vinto (di conseguenza l'altro ha perso) 
	 */
	public void winner(CheckerColor playerColor){

		// stampo le statistiche (unita' di misura ns)
		System.out.println("Statistiche finali");
		System.out.println("Tempo medio BLACK: "+Search.meanTime(true)+" ms");
		System.out.println("Tempo medio WHITE: "+Search.meanTime(false)+" ms");
		
		/* Il giocatore con il colore playerColor ha vinto */

		// arrivati qui non dovrebbero essere presenti ne placeholder ne pedine evidenziate

		endWind = new JDialog(this);	

		endWind.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		endWind.addWindowListener(this);
		endWind.setBackground(new Color(139,69,19));
		endWind.setTitle("FINE PARTITA");
		endWind.setResizable(false);

		// il pannello che contiene tutti gli altri pannelli
		JPanel endPane = new JPanel();
		endPane.setBackground(endWind.getBackground());
		endPane.setLayout(new BoxLayout(endPane, BoxLayout.Y_AXIS));

		// il pannello che contiene il testo
		JPanel endRes = new JPanel();
		endRes.setBackground(endWind.getBackground());
		endRes.setLayout(new BoxLayout(endRes, BoxLayout.X_AXIS));


		// il testo
		JTextPane endText= new JTextPane();
		endText.setBackground(endWind.getBackground());
		endText.setEditable(false);
		StyledDocument doc = endText.getStyledDocument();      
		SimpleAttributeSet textStyle = new SimpleAttributeSet();
		StyleConstants.setForeground(textStyle,Color.BLACK);
		StyleConstants.setFontSize(textStyle, 16);
		StyleConstants.setBold(textStyle,true);

		String winner=null;

		if(playerColor==CheckerColor.WHITE){
			winner="bianco";

		}
		else{

			winner="nero";
		}

		try {
			doc.insertString(doc.getLength(), "  Il giocatore " + winner +" ha vinto la partita.  " , textStyle);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}

		endRes.add(endText);

		//centra la scritta
		SimpleAttributeSet center = new SimpleAttributeSet();
		StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
		doc.setParagraphAttributes(0, doc.getLength(), center, false);

		//tasto OK
		JPanel endBtnPane = new JPanel();
		endBtnPane.setBackground(endWind.getBackground());
		endBtnPane.setLayout(new BoxLayout(endBtnPane, BoxLayout.X_AXIS));
		//tasto esci
		JButton endExit =new JButton("Esci");
		endExit.addActionListener(this);
		endExit.setActionCommand("endExit");
		endBtnPane.add(endExit);
		endBtnPane.add(Box.createRigidArea(new Dimension(10,0)));
		//tasto ricomincia
		JButton endRestart =new JButton("Ricomincia");
		endRestart.addActionListener(this);
		endRestart.setActionCommand("endRestart");
		endBtnPane.add(endRestart);

		endPane.add(Box.createRigidArea(new Dimension(0,3)));
		endPane.add(endRes);
		endPane.add(Box.createRigidArea(new Dimension(0,10)));
		endPane.add(endBtnPane);
		endPane.add(Box.createRigidArea(new Dimension(0,10)));

		endWind.setContentPane(endPane);

		endWind.setModal(true); //non devo piu' interagire con la GUI

		endWind.pack();

		endWind.setLocationRelativeTo(null); //al centro dello schermo

		endWind.setVisible(true);

	}


	/**
	 * Ottiene i valori dei dadi per lo spareggio iniziale ed eventualmente avvia il primo turno di gioco
	 * @param diceBlack il dado del giocatore nero
	 * @param diceWhite il dado del giocatore bianco
	 */
	private void tieBreaker(int diceBlack,int diceWhite){


		// ho ricevuto i valori dei dadi dello spareggio

		if(diceBlack==diceWhite){
			// stesso valore, lo spareggio deve essere rieseguito
			initGame();	
			return;
		}


		Player firstPl = null;

		if(diceBlack < diceWhite){
			// deve iniziare il giocatore bianco
			firstPl=whitePl;
			System.out.println("Inizia la partita il giocatore bianco"); 
		}
		else if (diceWhite < diceBlack){
			// deve iniziare il giocatore nero
			firstPl=blackPl;
			System.out.println("Inizia la partita il giocatore nero");
		}

		// imposto chi inizia il turno
		bg.setPlayerTurn(firstPl.getColor());

		Search.resetStats();
		
		// avvia il primo turno
		newTurn(firstPl);


	}


	/**
	 * Inizia il turno di un player
	 */
	private void newTurn(Player pl){

				
		CheckerColor color=((AbstractPlayer)pl).getColor();

		//coloro i dadi del colore del player che ha il turno
		if(color==CheckerColor.BLACK){

			//e' il turno del player nero

			//System.out.println("E' il turno del player nero");

			dice1.setDiceColor(Color.BLACK, Color.WHITE);
			dice2.setDiceColor(Color.BLACK, Color.WHITE);

		}
		else if(color==CheckerColor.WHITE){

			//e' il turno del player bianco
			//System.out.println("E' il turno del player bianco");

			dice1.setDiceColor(Color.WHITE, Color.BLACK);
			dice2.setDiceColor(Color.WHITE, Color.BLACK);
		}

		if(pl.isHuman()){

			// inizia un giocatore umano
			// evidenzio i dadi dell'interfaccia grafica per segnalare all'utente che deve premerne uno
			enableDice(dice1);
			enableDice(dice2);

		}

		else{ //IA
			
			
			if(pauseEnabled){ // se la pausa e' attiva, il calcolo della mossa deve essere richiamato con il tasto step
				
				//riattivo il tasto step (se non e' gia' attivo)
				
				if(!stepBtn.isEnabled()){
					// TODO quando si attende che il tasto step venga premuto questo puo' essere evidenziato
					stepBtn.setEnabled(true);
				}
				
				return;
				
			}
			
			else{ //se la pausa non e' attiva procedi al calcolo della mossa senza attendere
				
				computeIAmove(pl);
			}


		}


	}

	
	/**
	 * Calcola la mossa dell'IA
	 * @param pl l'istanza player dell'IA
	 */
	private void computeIAmove(Player pl){
		
		//chiedo a Backgammon di generare i valori per il tiro dei dadi

		int dice1Value = bg.rollDice();
		int dice2Value = bg.rollDice();

		// i dadi vengono aggiornati automaticamente
		dice1.setValue(dice1Value);
		dice2.setValue(dice2Value);

		System.out.println("Il player "+pl+" (IA) ha tirato i dadi: ("+dice1Value+","+dice2Value+")");
		bg.setRoll(dice1.getValue(), dice2.getValue());

		if (bg.noLegalPositions(dice1Value, dice2Value)) {

			System.out.println("Nessuna mossa per il giocatore "+pl+ " (IA)");
			
			if (bg.tooglePlayerTurn().isBlack()) {
				// tocca al nero
				newTurn(blackPl);
			} else {
				newTurn(whitePl);
			}

		} else {

			boolean isMaxNode;
			CheckerColor col= bg.whoseTurnIsIt();
			if (BoardType.color2type(col).equals(BoardType.MAX)) {
				isMaxNode= true;
			} else {
				isMaxNode= false;
			}
			bg.setSilent(true);
			
			// lancio elaborazione su thread in background rispetto a quello della grafica
			AIBrain worker = new AIBrain(bg,isMaxNode,pl);
			worker.execute();
			
		}
		
	}


	/**
	 * Abilita il dado per permettere ad un player umano di effettuare il suo tiro
	 * @param dice il dado da abilitare
	 */
	private void enableDice(Dice dice){

		Cursor handCurs = new Cursor(Cursor.HAND_CURSOR);
		dice.setCursor(handCurs);

		//evidenzio il bordo del dado
		if(!dice.isHighlighted()){
			dice.setHighlight(true);
		}

		dice.setEnabled(true);
	}

	/**
	 * Disabilita il dado quando il player non puo' cliccarci sopra per effettuare il tiro
	 * @param dice il dado da disabilitare
	 */
	private void disableDice(Dice dice){

		dice.setCursor(null);

		//tolgo l'evidenziazione del bordo del dado		
		if(dice.isHighlighted()){
			dice.setHighlight(false);
		}

		dice.setEnabled(false);

	}


	/**
	 * Evidenzia tutte le pedine che il player umano puo' muovere altrimenti ne abilita solo il click
	 * @param color il colore del player che deve muovere
	 */
	private void highlightAllCheckers(CheckerColor color){


		if(bg.getBarCheckers(color)!=0){ //se player ha pedine sulla bar andra' evidenziata l'ultima aggiunta per poterla riportare in gioco

			bar.highlightChecker(color);

			// una volta evidenziato posso cliccarci sopra nella GUI

		}

		else{ //il player puo' muovere le pedine sulla tavola

			for(PointLabel pl: pointsList){

				//evidenzio nel point solo le pedine con lo stesso colore di quelle del giocatore che ha il turno
				CheckerColor col= pl.getPoint().getColor();

				if(col!=null && col==bg.whoseTurnIsIt()){

					// controllo se con i dadi che ho tirato ci sono mosse possibili partendo da questa punta

					try {
						if(!(bg.noLegalPositions(pl.getPoint().getPosition(),move))){
							// si puo' effettuare una mossa con la pedina su questo point

							pl.highlightChecker();

						}
					} catch (DiceException e) {
						throw new BackgammonError(bg, "La mossa non e' valida", e);
					} catch (PositionException e) {
						throw new BackgammonError(bg, "La mossa non e' valida", e);
					} catch (BadMoveException e) {
						throw new BackgammonError(bg, "La mossa non e' valida", e);
					}

				}

			}

		}

	}


	/**
	 * Rimuove l'evidenziazione dai checkers del player umano
	 */
	private void removeCheckersHighlight(){


		CheckerColor color= bg.whoseTurnIsIt();

		//se ho pedine sulla bar andra' rimossa la loro evidenziazione
		if(bg.getBarCheckers(color)!=0){ // il player umano ha fattto click sulla pedina sul bar

			bar.disableHighlight(color);

		}

		for(PointLabel pl: pointsList){

			//deseleziono nel point solo le pedine con lo stesso colore di quelle del giocatore che ha il turno (perche' le altre non le avevo evidenziate)
			CheckerColor col= pl.getPoint().getColor();

			if(col!=null && col==color){
				pl.disableHighlightChecker();
			}

		}

	}


	@Override
	public void actionPerformed(ActionEvent e) {

		String action = e.getActionCommand();

		if(action.equals("Dice1") || action.equals("Dice2")){

			//qui si arriva con il click del player umano su uno dei 2 dadi

			CheckerColor plColor= bg.whoseTurnIsIt(); // chiedo a Backgammon di chi e' il turno...

			if(plColor==null){ //...se il metodo ritorna null non e' ancora terminato lo spareggio

				if(action.equals("Dice1")){
					//e' stato appena tirato il dado nero (il primo) per fare lo spareggio

					int dice1Value = bg.rollDice();

					dice1.setValue(dice1Value);
					System.out.println("Il player nero (umano) ha tirato il dado dello spareggio: "+dice1Value);

					disableDice(dice1);

					//tocca al giocatore bianco tirare il dado
					if(whitePl.isHuman()){ //e' umano attendo che faccia click

						enableDice(dice2);

					}

					else{ //IA

						//tiro automatico
						int dice2Value = bg.rollDice();

						dice2.setValue(dice2Value);

						System.out.println("Il player bianco (IA) ha tirato il dado dello spareggio: "+dice2Value);


						tieBreaker (dice1Value,dice2Value);

					}

				}

				else{
					//e' stato appena tirato il dado bianco per lo spareggio; siccome questo viene sempre tirato dopo quello nero, i 2 dadi sono gia' stati tirati

					int dice2Value = bg.rollDice();

					dice2.setValue(dice2Value);

					System.out.println("Il player bianco (umano) ha tirato il dado dello spareggio: "+dice2Value);

					disableDice(dice2);

					//controllo chi deve iniziare il turno
					tieBreaker (dice1.getValue(),dice2Value);

				}


				return;

			}


			String cl=null;

			if(plColor==CheckerColor.BLACK){

				cl="nero";

			}

			else{ //bianco

				cl="bianco";
			}


			//tiro il dado1
			int dice1Value = bg.rollDice();

			//aggiorno il valore sul dado1
			dice1.setValue(dice1Value);

			System.out.println("Il player "+cl+" (umano) ha tirato il dado1: "+dice1Value);

			//tiro il dado2
			int dice2Value = bg.rollDice();

			//aggiorno il valore sul dado2
			dice2.setValue(dice2Value);

			System.out.println("Il player "+cl+" (umano) ha tirato il dado2: "+dice2Value);

			//disabilito i dadi
			disableDice(dice1);
			disableDice(dice2);
			move= new Move(dice1.getValue(), dice2.getValue(), plColor);

			System.out.println("Il player "+cl+" (umano) ha tirato i dadi: ("+dice1Value+","+dice2Value+")");
			bg.setRoll(dice1.getValue(), dice2.getValue());

			if (bg.noLegalPositions(dice1Value, dice2Value)) {
				// questo giocatore non puo' muovere
				System.out.println("Nessuna mossa per il giocatore "+cl+ " (umano)");
				JOptionPane.showMessageDialog(this, "Nessuna mossa");

				if (bg.tooglePlayerTurn().isBlack()) {
					// tocca al nero
					newTurn(blackPl);
				} else {
					newTurn(whitePl);
				}

			} else {
				// adesso evidenzio tutte le pedine su cui il player puo' fare click e attendo che faccia la sua mossa

				highlightAllCheckers(plColor);
			}

		}

		else if(action.equals("endExit")){ //premuto tasto esci nella endWind


			endWind.dispose(); // chiudo finestra winner
			endWind=null;
			this.dispose(); // chiudo BackgammonGUI
			//chiudo finestra iniziale
			if(initWindow!=null){
				initWindow.dispose();
				initWindow=null;
			}

			System.exit(0);
		}

		else if(action.equals("endRestart")){ //premuto tasto ricomincia nella endWind

			endWind.dispose(); // chiudo finestra winner
			endWind=null;
			this.dispose(); // chiudo BackgammonGUI
			//riapre finestra iniziale
			if(initWindow==null){
				System.err.println("La finestra iniziale non e' stata impostata nella BackgammonGUI. Impossibile ricominciare");
				System.exit(1);
			}
			else{
				initWindow.setVisible(true);
			}

		}
		
		else if(action.equals("pause")){ // premuto il tasto pause
			
			if(!pauseEnabled){
				pauseEnabled=true;
				try {
				    Image img = ImageIO.read(BackgammonGUI.class.getResource("/img/play.png"));
				    img=img.getScaledInstance(50, 50, Image.SCALE_SMOOTH);
				    pauseBtn.setIcon(new ImageIcon(img));
				  } catch (IOException ex) {
				  }
				
			}
			else if(pauseEnabled && stepBtn.isEnabled()){ // stavo attendendo che la mossa venisse fatta e ho ripremuto il tasto pausa
				
				
				if(bg.whoseTurnIsIt().isBlack()){
					computeIAmove(blackPl);
				}
				else{
					computeIAmove(whitePl);
				}
				
				stepBtn.setEnabled(false);
				
				// voglio ripartire con l'esecuzione alla velocita massima
				pauseEnabled=false;
				try {
				    Image img = ImageIO.read(BackgammonGUI.class.getResource("/img/pause.png"));
				    img=img.getScaledInstance(50, 50, Image.SCALE_SMOOTH);
				    pauseBtn.setIcon(new ImageIcon(img));
				  } catch (IOException ex) {
				  }
				
			}
			
		}
		
		else if (action.equals("step")){ // premuto il tasto step
			
			//se la pausa e' abilitata posso eseguire la mossa
			
			if(pauseEnabled){
				if(bg.whoseTurnIsIt().isBlack()){
					computeIAmove(blackPl);
				}
				else{
					computeIAmove(whitePl);
				}
				
				// disabilito il tasto step, verra' riattivato (se la pausa e' ancora abilitata alla fine dell'esecuzione della mossa)
				stepBtn.setEnabled(false);
			}
			
		}

	}

	/**
	 * Rimuove i placeholder presenti sulle tavole
	 */
	private void removePlaceholders(){

		for(PointLabel pl: pointsList){
			pl.hidePlaceholder();
		}

		bearOffBar.removePlaceHolder(CheckerColor.WHITE);
		bearOffBar.removePlaceHolder(CheckerColor.BLACK);

		this.isPlaceholderShown=false;
	}

	/**
	 * Aggiunge i placeholder in corrispondenza delle posizioni in cui si puo' muovere il player
	 * @param points le posizioni in cui si puo' muovere il player
	 */
	private void addPlaceholders(Set<Integer> points){

		CheckerColor col=bg.whoseTurnIsIt();


		for(int p : points){

			if(p==Backgammon.OFF){ //il player puo' fare uscire la pedina

				bearOffBar.addChecker(col, true);
			}
			else{

				//recupera PointLabel corrispondenti alle legal position restituite e inserisci segnaposto
				pointsList.get(p-1).insertChecker(col, true);
			}

		}

		this.isPlaceholderShown=true;
	}


	@Override
	public void mouseClicked(MouseEvent e) {

		if (e.getClickCount()!=1) return;

		// ricavo il colore del player che ha il turno
		CheckerColor col=bg.whoseTurnIsIt();

		if(!(e.getComponent() instanceof Checker)){ // se non  ho cliccato su un checker significa che voglio cambiare la mossa che ho fatto

			if(this.isPlaceholderShown){ // i placeholder sono mostrati (nessun checker e' quindi evidenziato)

				//rimuovo i placeholder
				removePlaceholders();

				//evidenzio nuovamente i checkers
				highlightAllCheckers(col);

			}

			initPos=-10;

			return;

		}


		if(!this.isPlaceholderShown){ //le pedine del player sono ancora evidenziate
			//tolgo evidenziazione da tutte le pedine (adesso e' il momento di mostrare i segnaposto)		
			removeCheckersHighlight();
		}

		//ho cliccato su di un checker (che potrebbe anche essere un segnaposto)

		Checker checker = (Checker) e.getComponent();

		// ricavo la posizione del checker (in questo caso position == posizione iniziale) o placeholder (in questo caso position==posizione finale) su cui ho cliccato
		int position=checker.getPosition();


		if(checker.isPlaceHolder()){ //il player umano ha fatto click su un placeHolder per spostare li' la propria pedina

			//rimuovo i placeholder
			removePlaceholders();
			
			CheckerMove chkMove =null;
			
			try {

				chkMove= bg.generateCheckerMove(initPos, position, move);
				move.add(chkMove);
				bg.partialMove(chkMove);

			} catch (BadMoveException e1) {
				throw new BackgammonError(bg, "Eccezione nella generazione della mossa", e1);
			}			
			

			if(position!=initPos){ // posizione iniziale != posizione finale percio' eseguo lo spostamento
				
				if(initPos==-10){

					throw new PositionException(initPos, "La posizione iniziale dello spostamento non e' stata memorizzata.");

				}
				
				for (SingleMove sm : chkMove) {
					int startPos=sm.getStartingPosition();
					int endPos=sm.getEndingPosition();
					
					
					//point di partenza
					
					if(Backgammon.isBar(startPos)){ // il checker partiva dal bar

						bar.removeChecker(col);

					}
					else if(Backgammon.isOnTable(startPos)){ //il checker partiva dalla tavola

						if(col.isBlack())
							System.out.println("Il player nero ha rimosso una pedina dalla punta "+startPos);
						else
							System.out.println("Il player bianco ha rimosso una pedina dalla punta "+startPos);

						//rimuovo la pedina dalla posizione in cui si trovava prima
						pointsList.get(startPos-1).removeChecker();

					}
					
					//point di destinazione
					
					if((endPos!=Backgammon.OFF) && sm.isHit()){
						// la destinazione e' un point in cui e' presente solo una pedina dell'altro player (devo mangiarla)
						
						if(bg.whoseTurnIsIt().isBlack()){

							bar.addChecker(CheckerColor.WHITE);

						}
						else{

							bar.addChecker(CheckerColor.BLACK);


						}

						pointsList.get(endPos-1).removeChecker();

					}
					
					
					if(Backgammon.isOff(endPos)){ // la posizione finale e' l'uscita della pedina fuori dalla tavola

						// aggiungo il checker nella barra di off
						bearOffBar.addChecker(col, false);

						if(col.isBlack())
							System.out.println("Il player nero ha portato fuori la "+bg.getBorneOffCheckers(col)+" pedina");
						else
							System.out.println("Il player bianco ha portato fuori la "+bg.getBorneOffCheckers(col)+" pedina");

						if(bg.getBorneOffCheckers(col)==15){
							bg.setSilent(false);
							try {
								if (!bg.move(move)) {
   									throw new BackgammonError(bg, ""+col + " avrebbe dovuto vincere");
   								}
								System.out.println("Tempo medio BLACK: "+Search.meanTime(true)+" ms");
								System.out.println("Tempo medio WHITE: "+Search.meanTime(false)+" ms");
							} catch (BadMoveException e1) {
								throw new BackgammonError(bg, "Eccezione in mossa validata");
							}
							winner(col);
							return;
						}

					}

					else if(Backgammon.isOnTable(endPos)){ // la posizione finale e' su un altro point

						// aggiungo la pedina nella nuova posizione
						pointsList.get(endPos-1).insertChecker(col, false);

						if(col.isBlack())
							System.out.println("Il player nero ha aggiunto la pedina nella punta "+endPos);
						else
							System.out.println("Il player bianco ha aggiunto la pedina nella punta "+endPos);

					}

					else{

						throw new BackgammonError(bg, "La posizione di destinazione puo' essere solamente un point o la bear off bar");

					}
					
					
					
				}



			}

			//else il player ha fatto click sullo stesso checker che voleva spostare (initPos==position) per cui non rimuovo alcuna mossa da possibleMoves

			// se le mosse che il player puo' compiere sono finite passo il turno
			try {
				if(bg.noLegalPositions(move)){

					try {
						bg.move(move);
						System.out.println("Tempo medio BLACK: "+Search.meanTime(true)+" ms");
						System.out.println("Tempo medio WHITE: "+Search.meanTime(false)+" ms");
					} catch (BadMoveException e1) {
						throw new BackgammonError(bg, "Eccezione nella esecuzione della mossa", e1);
					}

					
					checkConsistency();
					
					// metto move a null
					move=null;

					//passo il turno
					CheckerColor plColorTurn = bg.tooglePlayerTurn();
					if(plColorTurn==CheckerColor.WHITE)
						this.newTurn(whitePl);
					else 
						this.newTurn(blackPl);
				}

				else{ //altrimenti evidenzio nuovamente le pedine (il player puo' ancora muovere)

					highlightAllCheckers(col);
				}

			} catch (BadMoveException e1) {
				throw new BackgammonError(bg, "Eccezione nella esecuzione della mossa", e1);
			}

			return;

		}


		// il player ha selezionato un checker che non e' un placeHolder (il checker puo' trovarsi sul bar o su un point)

		// viene visualizzato dove il player puo' muovere quel checker

		// il checker su cui il player ha cliccato deve avere lo stesso colore del player che ha il turno
		if(checker.getColor()!=col){
			throw new BackgammonError(bg, "Il player ha avuto la possibilita' di cliccare su una pedina non sua");
		}

		// imposto la posizione di partenza dello spostamento
		initPos=position;

		Set<Integer> points=null;

		try {
			points =bg.legalPositions(position, move);
		} catch (DiceException e1) {
			throw new BackgammonError(bg, "La mossa non e' valida", e1);
		} catch (PositionException e1) {
			throw new BackgammonError(bg, "La mossa non e' valida", e1);
		} catch (BadMoveException e1) {
			throw new BackgammonError(bg, "La mossa non e' valida", e1);
		}

		String cl=null;

		if(col==CheckerColor.BLACK){

			cl="nero";

		}

		else{ //bianco

			cl="bianco";
		}

		System.out.println("Il player "+ cl +" ha cliccato sulla pedina in posizione "+initPos);
		System.out.println("Le posizioni legali restituite sono: "+points);

		addPlaceholders(points);


	}


	@Override
	public void mousePressed(MouseEvent e) {

	}


	@Override
	public void mouseReleased(MouseEvent e) {

	}


	@Override
	public void mouseEntered(MouseEvent e) {

	}


	@Override
	public void mouseExited(MouseEvent e) {

	}

	@Override
	public void windowOpened(WindowEvent e) {

	}

	@Override
	public void windowClosing(WindowEvent e) {

		if(e.getSource()==endWind){ // finestra di vittoria 
			//chiusura finestra vincitore
			endWind.dispose();
			endWind=null;
			this.dispose(); //chiudo anche BackgammonGUI
			//riapre finestra iniziale

			if(initWindow==null){
				System.out.println("La finestra iniziale non e' stata impostata nella BackgammonGUI. Impossibile ricominciare");
				System.exit(1);
			}
			else{
				initWindow.setVisible(true);
			}
		}
	}

	@Override
	public void windowClosed(WindowEvent e) {

	}

	@Override
	public void windowIconified(WindowEvent e) {

	}

	@Override
	public void windowDeiconified(WindowEvent e) {

	}

	@Override
	public void windowActivated(WindowEvent e) {

	}

	@Override
	public void windowDeactivated(WindowEvent e) {

	}

	public class AIBrain extends SwingWorker<Move, Void>{
						  
		  private boolean isMaxNode;
		  
		  private Backgammon bg;
		  
		  private Player player;
		  
		  public AIBrain(Backgammon bg, boolean isMaxNode, Player player){
			  
			  this.bg=bg;
			  this.isMaxNode=isMaxNode;
			  this.player=player;
			  
		  }
			
	       @Override
	       public Move doInBackground() {
	         try {
				TimeUnit.SECONDS.sleep(BackgammonGUI.SECONDS);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	         
	         Move aiMove = player.bestMove(bg);
	         return aiMove;
	       }
	       
	       
	       @Override
	       public void done() {
	    	   CheckerColor col= player.getColor();

	    	   try {
	    		   Move aiMove = get();

	    		   for (SingleMove sm : aiMove) {

	    			   try {
	    				   bg.partialMove(sm);
	    			   } catch (BadMoveException e) {
	    				   throw new BackgammonError(bg, "Player.bestMove() ha restituito "+aiMove+", ma una delle mosse parziali non e' corretta", e);
	    			   }


	    			   // ricavo la posizione del checker
	    			   int startPos= sm.getStartingPosition();
	    			   int position= sm.getEndingPosition();


	    			   boolean mustHit= sm.isHit();

	    			   if(position!=startPos){ // posizione iniziale != posizione finale percio' eseguo lo spostamento

	    				   if(Backgammon.isBar(startPos)){ // il checker partiva dal bar

	    					   bar.removeChecker(col);

	    				   }

	    				   else if(Backgammon.isOnTable(startPos)){ //il checker partiva dalla tavola

	    					   if(col.isBlack())
	    						   System.out.println("Il player nero (IA) ha rimosso una pedina dalla punta "+startPos);
	    					   else
	    						   System.out.println("Il player bianco (IA) ha rimosso una pedina dalla punta "+startPos);

	    					   //rimuovo la pedina dalla posizione in cui si trovava prima
	    					   pointsList.get(startPos-1).removeChecker();

	    				   }


	    				   if(mustHit){
	    					   // la destinazione e' una point in cui e' presente solo una pedina dell'altro player (devo mangiarla)
	    					   if(bg.whoseTurnIsIt().isBlack()){

	    						   bar.addChecker(CheckerColor.WHITE);

	    					   }
	    					   else{

	    						   bar.addChecker(CheckerColor.BLACK);


	    					   }

	    					   pointsList.get(position-1).removeChecker();

	    				   }

	    				   if(Backgammon.isOff(position)){ // la posizione finale e' l'uscita della pedina fuori dalla tavola

	    					   // aggiungo il checker nella barra di off
	    					   bearOffBar.addChecker(col, false);

	    					   if(col.isBlack())
	    						   System.out.println("Il player nero ha portato fuori la "+bg.getBorneOffCheckers(col)+" pedina");
	    					   else
	    						   System.out.println("Il player bianco ha portato fuori la "+bg.getBorneOffCheckers(col)+" pedina");

	    					   if(bg.getBorneOffCheckers(col)==15){
	    						   bg.setSilent(false);
		   							try {
		   								if (!bg.move(aiMove)) {
		   									throw new BackgammonError(bg, ""+col + " avrebbe dovuto vincere");
		   								}
		   								System.out.println("Tempo medio BLACK: "+Search.meanTime(true)+" ms");
		   								System.out.println("Tempo medio WHITE: "+Search.meanTime(false)+" ms");
									} catch (BadMoveException e1) {
										throw new BackgammonError(bg, "Eccezione in mossa validata");
									}
	    						   winner(col);
	    						   return;
	    					   }

	    				   }

	    				   else if(Backgammon.isOnTable(position)){ // la posizione finale e' su un altro point

	    					   // aggiungo la pedina nella nuova posizione
	    					   pointsList.get(position-1).insertChecker(col, false);

	    					   if(col.isBlack())
	    						   System.out.println("Il player nero ha aggiunto la pedina nella punta "+position);
	    					   else
	    						   System.out.println("Il player bianco ha aggiunto la pedina nella punta "+position);

	    				   }

	    				   else{

	    					   throw new BackgammonError(bg, "La posizione di destinazione puo' essere solamente un point o la bear off bar");

	    				   }



	    			   }

	    			   //else il player ha fatto click sullo stesso checker che voleva spostare (initPos==position) per cui non eseguo alcuno spostamento






	    		   }

	    		   bg.setSilent(false);

	    		   // modifico la struttura dati
	    		   try {
	    			   bg.move(aiMove);
	    				System.out.println("Tempo medio BLACK: "+Search.meanTime(true)+" ms");
	    				System.out.println("Tempo medio WHITE: "+Search.meanTime(false)+" ms");
	    		   } catch (BadMoveException e) {
	    			   throw new BackgammonError(bg, "La mossa restituita da Player.bestMove() non e' corretta", e);
	    		   }

	    		   checkConsistency();

	    		   if (bg.tooglePlayerTurn().isBlack()) {
	    			   // tocca al nero
	    			   newTurn(blackPl);
	    		   } else {
	    			   newTurn(whitePl);
	    		   }

	    	   } catch (InterruptedException ex) {
	    		   ex.printStackTrace();
	    	   } catch (ExecutionException ex) {
	    		   ex.printStackTrace();
	    	   }



	       }


	}
	
	
	/**
	 * Controlla che lo stato della grafica sia equivalente allo stato interno di Backgammon
	 * Se non vi e' coerenza tra gli stati lancia un'eccezione per terminare il programma
	 */
	public void checkConsistency() {
		
		// verifico i checker nelle punte
		for(PointLabel pl:pointsList){
			
			int pointNum =pl.getPoint().getPosition();
			
			if(pl.getPoint().getColor()!=pl.getCheckerColor()){ // il colore dei checker sul point e' diverso
				
				throw new BackgammonError(bg, "checkConsistency: il colore dei checkers sul point "+ pointNum+ " non corrisponde.");
				
			}
			
			
			int bgChNum=pl.getPoint().getNum();
			int GUIChNum=pl.getNumCheckers();
			
			if(bgChNum!=GUIChNum){ // il numero di checker sul point non corrisponde
				
				throw new BackgammonError(bg, "checkConsistency: il numero dei checkers sul point "+ pointNum+ " non corrisponde: "+bgChNum+"!="+GUIChNum);

			}
			
			
		}
		
		// verifico i checker sul bar

		
		int bgBarBlackNum=bg.getBarCheckers(CheckerColor.BLACK);
		int GUIBarBlackNum=bar.getNumBarCheckers(CheckerColor.BLACK);
				
		if(bgBarBlackNum!=GUIBarBlackNum){
			
			throw new BackgammonError(bg, "checkConsistency: il numero dei checkers neri sulla bar non corrisponde: "+bgBarBlackNum+"!="+GUIBarBlackNum);

		}
		
		int bgBarWhiteNum=bg.getBarCheckers(CheckerColor.WHITE);
		int GUIBarWhiteNum=bar.getNumBarCheckers(CheckerColor.WHITE);
		
		if(bgBarWhiteNum!=GUIBarWhiteNum){
			
			throw new BackgammonError(bg, "checkConsistency: il numero dei checkers bianchi sulla bar non corrisponde: "+bgBarWhiteNum+"!="+GUIBarWhiteNum);

		}
		
		
		// verifico i checker nel bearOff

		
		int bgBorneOffBlackNum=bg.getBorneOffCheckers(CheckerColor.BLACK);
		int GUIBorneOffBlackNum=bearOffBar.getNumBarCheckers(CheckerColor.BLACK);
		
		
		if(bgBorneOffBlackNum!=GUIBorneOffBlackNum){
			
			throw new BackgammonError(bg, "checkConsistency: il numero dei checkers neri portati fuori non corrisponde: "+bgBorneOffBlackNum+"!="+GUIBorneOffBlackNum);

		}
		
		
		int bgBorneOffWhiteNum=bg.getBorneOffCheckers(CheckerColor.WHITE);
		int GUIBorneOffWhiteNum=bearOffBar.getNumBarCheckers(CheckerColor.WHITE);
		
		if(bgBorneOffWhiteNum!=GUIBorneOffWhiteNum){
			
			throw new BackgammonError(bg, "checkConsistency: il numero dei checkers bianchi portati fuori non corrisponde: "+bgBorneOffWhiteNum+"!="+GUIBorneOffWhiteNum);

		}
		
		
	}
	
	
}
